/*
 * Copyright 2013 Walter Lütgenau.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package offset.nodes.client.dialog.navigation.view;

import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import offset.nodes.client.chooser.model.FolderNode;
import offset.nodes.client.chooser.model.NodeChooserModel;
import offset.nodes.client.chooser.view.LazyExpandingNode;
import offset.nodes.client.chooser.view.NodeRendererFactory;
import offset.nodes.client.dialog.navigation.model.NodeSelectionListener;
import offset.nodes.client.dialog.navigation.model.ServiceClient;
import offset.nodes.client.model.Server;

/**
 *
 * @author Walter Lütgenau
 */
public class RepositoryPanel extends AbstractCardPanel implements ServiceClient {
    String path;
    Server server;
    NodeChooserModel model;
    TreeNode node = null;
    LazyExpandingNode root = null;
    TreeExpansionHandler treeExpansionHandler = null;
    TreeSelectionHandler treeSelectionHandler = null;
    private NodeSelectionListener nodeSelectionListener = null;

    // Inner class that handles Tree Expansion Events
    protected class TreeExpansionHandler
            implements TreeExpansionListener {

        public void treeExpanded(TreeExpansionEvent evt) {
            TreePath path = evt.getPath();// The expanded path
            JTree tree =
                    (JTree) evt.getSource();// The tree

            // Get the last component of the path and
            // arrange to have it fully populated.
            LazyExpandingNode node =
                    (LazyExpandingNode) path.getLastPathComponent();
            try {
                if (node.populateChildren())
                    ((DefaultTreeModel) tree.getModel()).nodeStructureChanged(node);
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }

        public void treeCollapsed(TreeExpansionEvent evt) {
            // Nothing to do
        }
    }

    @Override
    public void setServer(Server server) {
        this.server = server;
        model = new NodeChooserModel(server);        
    }

    @Override
    public String getCardName() {
        return "repository";
    }
    
    protected class TreeSelectionHandler implements TreeSelectionListener {
           public void valueChanged(TreeSelectionEvent e) {
                if (repositoryTree.getSelectionCount() != 1)
                    return;

                TreePath path = repositoryTree.getSelectionPath();
                LazyExpandingNode node = (LazyExpandingNode) path.getLastPathComponent();
                FolderNode folder = (FolderNode) node.getUserObject();
                
                if (nodeSelectionListener != null)
                    nodeSelectionListener.nodeSelected(folder.getPath());
            }        
    }

    /**
     * A new node chooser panel.
     * 
     * @param server
     * @param path The path, from where the query starts
     * @param filter The filter, which will be executed on each expanding folder, starting from the path
     * @param onlyFolders Shall only folders (i.e. nodes with subnodes) be displayed?
     * @throws java.lang.Exception
     */
    public RepositoryPanel() throws Exception {
        this.server = server;
        initComponents();
        repositoryTree.setCellRenderer(NodeRendererFactory.createNodeRenderer());

        // Listen for Tree expansion Events
        treeExpansionHandler = new TreeExpansionHandler();
        
        // Listen for Tree selection events
        treeSelectionHandler = new TreeSelectionHandler();
    }
    
    /**
     * Add the nodes for the specified path.
     * 
     * @param path the path, for which nodes shall be added.
     * @throws Exception an exception
     */
    public void addPath(String path) throws Exception {
        if (path == null || path.length() == 0)
            path = "/";
        
        repositoryTree.removeTreeExpansionListener(treeExpansionHandler);
        repositoryTree.removeTreeSelectionListener(treeSelectionHandler);

        LazyExpandingNode oldRoot = root;
        root = model.initPath(root, path);
        
        TreePath treePath = new TreePath(((DefaultMutableTreeNode) getLeafNode(path.substring(1), root)).getPath());

        if (root != oldRoot)
            repositoryTree.setModel(new DefaultTreeModel(root));
        repositoryTree.setSelectionPath(treePath);
        repositoryTree.scrollPathToVisible(treePath);
        
        repositoryTree.addTreeExpansionListener(treeExpansionHandler);
        repositoryTree.addTreeSelectionListener(treeSelectionHandler);
    }
    
    public void setNodeSelectionListener(NodeSelectionListener nodeSelectionListener) {
        this.nodeSelectionListener = nodeSelectionListener;  
        repositoryTree.addTreeSelectionListener(treeSelectionHandler);
    }

    /**
     * Return the node denoted by path
     * 
     * @param path the path
     * @param root the root node
     * @return the node found
     */
    protected TreeNode getLeafNode(String path, TreeNode root) {
        String[] names = path.split("/");
        TreeNode node = root;
        for (String name : names) {
            for (int i = 0; i < node.getChildCount(); i++) {
                if (name.equals(node.getChildAt(i).toString())) {
                    node = node.getChildAt(i);
                    break;
                }
            }
        }

        return node;
    }



    /**
     * This method is called from within the constructor to initialize the form. WARNING: Do NOT
     * modify this code. The content of this method is always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        repositoryScrollPane = new javax.swing.JScrollPane();
        repositoryTree = new javax.swing.JTree();

        setLayout(new java.awt.BorderLayout());

        repositoryScrollPane.setBorder(null);

        repositoryTree.setBorder(javax.swing.BorderFactory.createEmptyBorder(5, 5, 5, 5));
        javax.swing.tree.DefaultMutableTreeNode treeNode1 = new javax.swing.tree.DefaultMutableTreeNode("root");
        repositoryTree.setModel(new javax.swing.tree.DefaultTreeModel(treeNode1));
        repositoryTree.setRowHeight(0);
        repositoryScrollPane.setViewportView(repositoryTree);

        add(repositoryScrollPane, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JScrollPane repositoryScrollPane;
    private javax.swing.JTree repositoryTree;
    // End of variables declaration//GEN-END:variables
}
